
/*
 * Este programa calcula 3 autovalores de una matriz cuadrada:
 *  -> El autovalor de menor valor absoluto y su autovector asociado.
 *  -> El autovalor de mayor valor absoluto y su autovector asociado.
 *  -> Un autovalor de valor absoluto intermedio y con su autovector asociado.
 * 
 * La matriz de la cual se obtienen los autovalores puede obtenerse de 3 maneras:
 *  -> Especificando el nombre del archivo que contiene sus valores.
 *  -> Ingresando los valores manualmente al inicio del programa.
 *  -> Pidiendo al programa que genere una matriz aleatoria.
 *
 * Este programa realiza los cálculos en solo proceso y no se paraleliza
 * ningún cálculo.
 *
 * Para el cálculo de los autovalores y autovectores, se utiliza el método
 * de las potencias.
 *
 */

/* Inclusión de bibliotecas propias */
#include "matrices.h"
#include "autovalores.h"
#include "inversa.h"
#include "entradasalida.h"

/* Inclusión de bicliotecas estandares */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>


/* Sección de implementación de funciones */

int main(void) {

    // Imprimimos la bienvenida
    printf("============================================================================\n");
    printf("Cálculo del menor/medio/mayor autovalor y su autovector. VERSIÓN SECUENCIAL\n");
    printf("============================================================================\n");

    // Aquí guardaremos la matriz con la cual haremos los cálculos y su tamaño.
    struct MATRIZ *matriz = obtenerMatrizDelUsuario();

    // En estas variables guardaremos los instantes en que el cálculo comienza
    time_t instanteInicial = time(NULL);
    
    // Calculamos el mayor autovalor y su autovector
    printf("\nCalculamos el mayor autovalor y su autovector\n");
    struct VV_PROPIO *mayorVV = metodoPotencias(matriz);
    
    // Calculamos la inversa de matriz
    printf("Calculamos la inversa de la matriz\n");
    struct MATRIZ *matrizInvertida = inversa(matriz);

    // Si la matriz devuelta fue NULL, salir
    if (matrizInvertida==NULL) {
        printf("\nNo se pudo calcular la inversa de la matriz principal.\n\n");
        return EXIT_FAILURE;
    }

    // Calculamos el menor autovalor y su autovector
    printf("Calculamos el menor autovalor y su autovector\n");
    struct VV_PROPIO *menorVV = metodoPotencias(matrizInvertida);
    menorVV->autovalor = 1 / menorVV->autovalor;
    
    // Ya no necesitamos la matriz invertida
    eliminarMatriz(matrizInvertida);
    
    // Obtenemos un valor medio entre los autovalores extremos
    double s = aproximarAutovalorMedio(mayorVV->autovalor,menorVV->autovalor);

    // Creamos y calculamos la matriz modificada
    printf("Calculamos la matriz para el autovalor medio\n");
    restarIxs(matriz,s);
    
    // Invertimos la matriz modificada
    printf("Calculamos la inversa de la matriz obtenida\n");
    struct MATRIZ *matrizModificada = inversa(matriz);

    // Si la matriz devuelta fue NULL, salir
    if (matrizModificada==NULL) {
        printf("\nNo se pudo calcular la inversa de la matriz modificada.\n\n");
        return EXIT_FAILURE;
    }

    // Ya no necesitamos la matriz modificada
    eliminarMatriz(matriz);
    
    // Calculamos el autovalor medio y su autovector a partir de la matriz modificada
    printf("Calculamos el autovalor medio y su autovector\n");
    struct VV_PROPIO *medioVV = metodoPotencias(matrizModificada);
    medioVV->autovalor = (1 / medioVV->autovalor) + s;
    
    // Ya no necesitamos la matriz modificada
    eliminarMatriz(matrizModificada);

    // Guardamos el momento final
    time_t instanteFinal = time(NULL);
    
    // Imprimimos los autovalores y sus autovectores
    imprimir_VV_PROPIO("Mayor autovalor", mayorVV);
    imprimir_VV_PROPIO("Autovalor medio", medioVV);
    imprimir_VV_PROPIO("Menor autovalor", menorVV);

    // Calculamos e imprimimos el tiempo que tardó en ejecutarse el programa
    int tiempoEjecucion = difftime(instanteFinal,instanteInicial);
    printf("\nTiempo de ejecucion: %d segundos\n",tiempoEjecucion);

    // Guardamos los autovalores/autovectores calculados
    almacenar_VV_PROPIOs(menorVV,mayorVV,medioVV);

    // Limpiamos la memoria
    eliminar_VV_PROPIO(mayorVV);
    eliminar_VV_PROPIO(menorVV);
    eliminar_VV_PROPIO(medioVV);

    // Imprimimos la despedida
    printf("\n\n====================================================================\n");
    printf("Fin del programa\n");
    printf("====================================================================\n\n");

    return (EXIT_SUCCESS);
    
}
